import {DynamicForm} from './index.vue.d'
import {FormItemConfig} from "./ConfigType";
import RenderUtils from "./RenderUtils";
import typeOfUtils from "../../utils/type-of-utils";

export interface WatchPros {
  prop: string;
  unWatch: Function;
}

export interface CascadeEvent {
  prop?: string; // 监听的字段
  props?: string[]; // 监听的字段，这个优先级更低
  watch?: boolean; // 是否开启监听
  /**
   * @param formData
   * @param item 自己的配置
   * @param prop 监听的字段
   * @param value 监听字段的值
   */
  event(formData: object, item: FormItemConfig, prop: string, value: any): void | Promise<void>
}

/**
 * 数据类型
 */
export interface CascadeType {
  watch?: boolean; // 是否开启监听，默认全部用事件触发，开启监听，事件就不在触发
  events: CascadeEvent[]
}

export class CascadeUtils {
  /**
   * callback的watch确实是否是监听
   * @param cascade
   * @param callBack
   */
  static cascadeIsWatch(cascade: CascadeType, callBack: (e: CascadeEvent, watch: boolean) => void) {
    for (const e of cascade.events) {
      if (e.watch === true) {
        callBack(e, true)
      } else if (cascade.watch === true && e.watch !== false) {
        callBack(e, true)
      } else {
        callBack(e, false)
      }
    }
  }

  static needWatchProp(item: FormItemConfig) {
    const result: string[] = []
    const cascade = item.cascade;
    if (cascade) {
      CascadeUtils.cascadeIsWatch(cascade, (e, watch) => {
        if (watch) {
          if (e.prop) {
            result.push(e.prop)
          }
          if (e.props) {
            result.push(...e.props)
          }
        }
      })
    }
    return result
  }

  static async runEvents(vm: DynamicForm, prop: string, watch: boolean) {
    const awaitEvents: Promise<any>[] = []
    RenderUtils.formItemForEach(vm, (item) => {
      const run = (e: CascadeEvent) => {
        if (e.prop === prop) {
          const res = e.event(vm.formData, item, prop, vm.formData[prop])
          if (typeOfUtils.isPromise(res)) {
            // @ts-ignore
            awaitEvents.push(res)
          }
        } else if (e.props && e.props.length) {
          for (const p of e.props) {
            if (p === prop) {
              const res = e.event(vm.formData, item, prop, vm.formData[prop])
              if (typeOfUtils.isPromise(res)) {
                // @ts-ignore
                awaitEvents.push(res)
              }
            }
          }
        }
      }
      const cascade = item.cascade;
      if (cascade) {
        CascadeUtils.cascadeIsWatch(cascade, (e, w) => {
          if (watch && w) {
            run(e)
          } else {
            run(e)
          }
        })
      }
    })
    for (let awaitEvent of awaitEvents) {
      await awaitEvent
    }
  }

  static createPropWatch(vm: DynamicForm) {
    const watchProps: string[] = []
    RenderUtils.formItemForEach(vm, item => {
      const strings = CascadeUtils.needWatchProp(item);
      watchProps.push(...strings)
    })
    const removeWatch: number[] = []
    vm.watchProps.forEach((w, index) => {
      if (!watchProps.includes(w.prop)) {
        removeWatch.push(index)
        w.unWatch()
      }
    })
    removeWatch.reverse().forEach(i => {
      vm.watchProps.splice(i, 1)
    })
    watchProps.forEach(w => {
      const find = vm.watchProps.find(i => {
        return i.prop === w;
      })
      if (!find) {
        const unwatch = vm.$watch(() => vm.formData[w], async (val, oldVal) => {
          await CascadeUtils.runEvents(vm, w, true)
        }, {deep: true, immediate: true})
        vm.watchProps.push({
          unWatch: unwatch,
          prop: w
        })
      }
    })
  }
}










